
#pragma once
#include <map>
#include <string>
#include <d3dx9.h>
#include "character_define.h"
#include <WTypes.h>
#include "IArchive.h"
#include "goodlinklist.h"
#include "modelrcmgr.h"
class CSkeletonMesh;

using namespace std;



struct _AniAtrr
{	
	_AniAtrr() : byFPS(30),Blend(0.0f)
	{

	}
	void Serial(CIArchive& ar)
	{
		ar.Serial((char*)this,sizeof(_AniAtrr));
	}

	int hitstart[3];
	int hitend[3];
	int dummy[3];
	int showarrow[3];
	int sound[4];	
	float Blend;//set animation initial time
	byte byHit;
	byte byFPS;
};

class _AnimKeyList
{
	friend class CModelStructTransf;
public:
	_AnimKeyList() : m_pPosKey(NULL),
		m_pRotateKey(NULL),m_uPosKeyCount(0),m_uRotKeyCount(0)
	{

	}
	~_AnimKeyList()
	{
		if (m_pPosKey)
		{
			delete [] m_pPosKey;
		}

		if (m_pRotateKey)
		{
			delete [] m_pRotateKey;
		}
	}

	void Serial(CIArchive& ar)
	{
		ar.Serial(m_strName);
		SERIALMATR(ar,m_matOffset);
		ar.Serial(m_uPosKeyCount);
		ar.Serial(m_uRotKeyCount);
		if (ar.IsReading())
		{
			InitKey();
		}
		ar.Serial((char*)m_pPosKey,sizeof(_PosKey)*m_uPosKeyCount);
		ar.Serial((char*)m_pRotateKey,sizeof(_RotateKey)*m_uRotKeyCount);
	}

	inline _RotateKey* GetRotKey(const uint32& uIndex)
	{
		if (uIndex<m_uRotKeyCount)
		{
			return &m_pRotateKey[uIndex];
		}
		else
		{
			return NULL;
		}
		
	}
	inline _PosKey* GetPosKey(const uint32& uIndex)
	{
		if (uIndex<m_uPosKeyCount)
		{
			return &m_pPosKey[uIndex];
		}
		else
		{
			return NULL;
		}
		
	}

	inline _PosKey* GetEndPosKey()
	{
		if (m_uPosKeyCount)
		{
			return &m_pPosKey[m_uPosKeyCount-1];
		}
		else
		{
			return NULL;
		}
	}

	inline uint32 GetPosKeyCount() const
	{
		return m_uPosKeyCount;
	}

	inline uint32 GetRotKeyCount() const
	{
		return m_uRotKeyCount;
	}

protected:
	void InitKey()
	{
		if (m_uPosKeyCount)
		{
			m_pPosKey = new _PosKey[m_uPosKeyCount];
		}
		if (m_uRotKeyCount)
		{
			m_pRotateKey = new _RotateKey[m_uRotKeyCount];
		}
	}
protected:
	uint32 m_uPosKeyCount;
	uint32 m_uRotKeyCount;
	string          m_strName;
	D3DXMATRIX      m_matOffset;
   
	_PosKey*    m_pPosKey;
	_RotateKey* m_pRotateKey;	
};

class _Anim : public CModelRCBase
{
	friend class CModelStructTransf;
	friend class _Frame;
public:
	_Anim() : m_iBoneCount(0),m_iSocketCount(0),m_BShare(FALSE),m_pAnimKeyList(NULL),m_pAnimSocket(NULL)
	{
	}
	~_Anim()
	{
		if(m_pAnimKeyList)
		{
			delete [] m_pAnimKeyList;
		}
		if (m_pAnimSocket)
		{
			delete [] m_pAnimSocket;
		}

		GDeleteAndRemoveElements(m_listEvent);
	}
	virtual void Serial(CIArchive& ar)
	{
		m_Attr.Serial(ar);
		ar.Serial(m_iBoneCount);
		ar.Serial(m_iSocketCount);
		ar.Serial(m_uMaxTime);
		ar.Serial(m_strName);
		ar.Serial(m_BShare);
		if (ar.IsReading())
		{
			InitAniList(m_iBoneCount,m_iSocketCount);
		}

		for (int i=0;i<m_iBoneCount;++i)
		{
			ar.Serial(m_pAnimKeyList[i]);
		}

		for (int i=0;i<m_iSocketCount;++i)
		{
			ar.Serial(m_pAnimSocket[i]);
		}

		SerialGList(ar,m_listEvent);
	}

	inline const BYTE GetFPS() const
	{
		return m_Attr.byFPS;
	}
	inline const float GetBlend() const
	{
		return m_Attr.Blend;
	}

	void SetAnimIndex(const int& iIndex)
	{
		m_iAniIndex = iIndex;
	}

	BOOL SetEventFlag(const _AniEventType& eType,const _AniEventFLag& eFlag);
	_AnimEvent* UpdateEvent(const float& fTime);

protected:
	void InitAniList(const int& iBoneCount,const int& iSocketCount)
	{
		m_iBoneCount   = iBoneCount;
		m_iSocketCount = iSocketCount;
		if (m_iBoneCount)
		{
			m_pAnimKeyList = new _AnimKeyList[m_iBoneCount];
		}
		if (m_iSocketCount)
		{
			m_pAnimSocket = new _AnimKeyList[m_iSocketCount];
		}
	}
protected:	
	_AniAtrr m_Attr;
	int m_iBoneCount;
	int m_iSocketCount;
	UINT m_uMaxTime;
	string m_strName;
	_AnimKeyList* m_pAnimKeyList;
	_AnimKeyList* m_pAnimSocket;
	CGLinkedList<_AnimEvent*> m_listEvent;
	BOOL m_BShare;
protected://not save;
	int m_iAniIndex;

};


//---------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
class _FrameNode : public CGLLNode
{
	friend class _Frame;
	friend class CSkeletonMesh;
protected:
	_FrameNode() : m_uBoneID(0),m_fRotY(0.0f),m_uCurrRotKey(0),m_uCurrPosKey(0),
		m_pParentFram(NULL)		
	{
	}
public:
	_FrameNode(_Frame* pFram) : m_uBoneID(0),m_fRotY(0.0f),m_uCurrRotKey(0),m_uCurrPosKey(0),
		m_pParentFram(pFram)
	{
		D3DXMatrixIdentity(&m_matAnim);
	}

	~_FrameNode()
	{
		GDeleteAndRemoveElements(m_Children);
	}

	void SetMatrix(const D3DXMATRIX& mat)
	{
		m_matOrg = m_matAnim = mat;
	}

	void SetBoneID(const uint32& uID)
	{
		m_uBoneID = uID;
	}

	void SetName(const char* szName)
	{
		m_strName = szName;
	}
protected:
	void UpdateChildFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn);
	void UpdateFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn);
	void UpdateChildShadowFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn);
	void UpdateShadowFrame(CSkeletonMesh* pMesh,const D3DXMATRIX* pmatIn);
	void UpdateAnim(const float& fTime);
	void ResetAnim(const BOOL& bResetMat = FALSE);	
	
	inline uint32 GetBonID()
	{
		return m_uBoneID;
	}


protected:
	D3DXMATRIX m_matAnim;//m_matRot;

	uint32 m_uBoneID;
	string m_strName;
	//BOOL   m_bSpineID;
	CGLinkedList<_FrameNode*> m_Children;

private:


private:
	D3DXMATRIX m_matOrg;

	float m_fRotY;//current only used at spine bone;
	_Frame* m_pParentFram;

	uint32 m_uCurrRotKey;
	uint32 m_uCurrPosKey;
};

class _Frame : public CGLLNode
{
	friend class CSkeletonMesh;
public:
	_Frame(CSkeletonMesh* pSkeMesh) : m_pAnim(NULL),m_pSkelMesh(pSkeMesh),m_iAniPlayOption(_PlayOpt0),
		m_fLastPosZ(0.0f),m_bRestartFirstFrame(FALSE),m_fVelocity(0),m_fCurrTime(0)
	{
		m_RootFrameNode.m_pParentFram = this;
	}
	virtual ~_Frame()
	{
	}

	void CheckFrame(const float& fTime);
	void Update(const D3DXMATRIX* pmatIN);

	void UpdateShadow(const D3DXMATRIX* pmatIN);

	void SetAnim(_Anim* pAnim,const BOOL& bReset);

	void ResetAnim(const BOOL& bRestMat);

	inline _RotateKey* GetRotKey(const uint32& uBoneID,const uint32& uKeyIndex)
	{
		return m_pAnim->m_pAnimKeyList[uBoneID].GetRotKey(uKeyIndex);
	}

	inline _PosKey* GetPosKey(const uint32& uBoneID,const uint32& uKeyIndex)
	{
		return m_pAnim->m_pAnimKeyList[uBoneID].GetPosKey(uKeyIndex);
	}

protected:
	_FrameNode     m_RootFrameNode;
	_Anim*         m_pAnim;
	CSkeletonMesh* m_pSkelMesh;
	_AniPlayOption m_iAniPlayOption;
private:
	float m_fVelocity;
	float m_fCurrTime;

	float          m_fLastPosZ;
	BOOL           m_bRestartFirstFrame;
};
